<template>
  <div class="TaskGantt">
    <MyTabs
      v-if="scene === 'all'"
      v-model="query.deptId"
      :options="state.deptOptions"
      @update:model-value="methods.commonChange(5)"
    />
    <div class="flex items-center justify-between pb-16 pt-16">
      <form class="my-20 flex" @submit.prevent="methods.handleSearch">
        <n-space wrap :size="[16, 16]">
          <MyTQI v-if="scene === 'all'" :content-width="180">
            <AsyncSelect
              v-model:value="query.projectId"
              :options="state.projectOptions"
              placeholder="选择项目"
              @update:value="methods.commonChange(4)"
            />
          </MyTQI>
          <MyTQI :content-width="180">
            <AsyncSelect
              v-model:value="query.moduleId"
              placeholder="选择模块"
              :options="state.moduleOptions"
              label-key="teskName"
              value-key="id"
              @update:value="methods.commonChange(3)"
            />
          </MyTQI>
          <MyTQI :content-width="180">
            <AsyncSelect
              v-model:value="query.executor"
              :options="state.devOptions"
              label-key="personName"
              value-key="personId"
              placeholder="选择研发"
              @update:value="methods.commonChange(2)"
            />
          </MyTQI>
          <MyTQI :content-width="180">
            <AsyncSelect
              v-model:value="query.executionScope"
              placeholder="选择执行范围"
              :options="state.scopeOptions"
              label-key="executionScope"
              value-key="executionScope"
            />
          </MyTQI>
          <MyTQI :content-width="290">
            <AsyncSelect
              v-model:value="query.taskState"
              :options="state.statusOptions"
              placeholder="选择状态"
              :multiple="true"
              :filterable="false"
            />
          </MyTQI>
          <div class="flex-shrink-0">
            <n-button attr-type="submit" class="ml-20" type="primary">
              <i class="i-fe:search mr-4" />
              搜索
            </n-button>
            <n-button
              v-if="scene === 'self'"
              v-permission="`TaskModule:add`"
              class="ml-10"
              ghost
              type="primary"
              @click="() => drawerMethods.handleAdd()"
            >
              <i class="h-14" />
              添加任务
            </n-button>
            <n-button
              v-permission="`TaskModule:column`"
              class="ml-10"
              ghost
              type="primary"
              @click="handleEditCol"
            >
              <i class="h-14" />
              列设置
            </n-button>
            <n-button
              v-if="scene === 'self'"
              v-permission="`project_lock`"
              class="ml-10"
              ghost
              type="primary"
              :loading="state.lockLoading"
              @click="() => methods.setLock()"
            >
              <i class="h-14" />
              {{ state.isLock ? '解锁' : '锁定' }}
            </n-button>
          </div>
        </n-space>
      </form>
      <div class="flex items-center justify-between gap-x-10">
        <div class="cursor-pointer" @click="methods.handleToggleHoliday">
          <div v-if="state.showHoliday" class="text-14 color-#686F7C">隐藏休息日</div>
          <div v-else class="text-14 color-#686F7C">显示休息日</div>
        </div>
        <MyTabs
          v-model="state.scaleUnit"
          :options="state.timeOptions"
          @update:model-value="methods.handleToggleUnit"
        />
      </div>
    </div>
    <n-spin :show="state.loading">
      <div class="h-580 flex" style="width: 100%">
        <TaskTable
          ref="$taskTable"
          :scene="scene"
          :list="state.list"
          :have-column-keys="state.haveColumnKeys"
          @contextmenu="methods.handleTableMenu"
          @scroll="methods.handleTableScroll"
          @change-width="(w) => (state.tableWidth = w)"
          @reset="() => methods.getList(true)"
        />
        <div
          ref="$gantt"
          class="myGantt"
          :style="{ width: `calc(100% - ${state.tableWidth}px)` }"
        ></div>
      </div>
    </n-spin>
    <n-dropdown
      placement="bottom-start"
      trigger="manual"
      :x="state.x"
      :y="state.y"
      :options="state.handles"
      :show="state.showDropdown"
      :on-clickoutside="methods.handleClickOutSize"
      @select="methods.handleSelect"
    />
    <!-- 列设置 -->
    <MyModal ref="$form" :model-form="model" @submit="handleSubmitCol">
      <n-form-item path="columnSetting">
        <n-checkbox-group v-model:value="model.columnSetting">
          <n-descriptions bordered :column="1" label-placement="left">
            <n-descriptions-item v-for="item in state.columnOptions" :key="item.value">
              <template #label>
                <n-checkbox :value="item.value" />
              </template>
              <div class="w-440">{{ item.label }}</div>
            </n-descriptions-item>
          </n-descriptions>
        </n-checkbox-group>
      </n-form-item>
    </MyModal>
    <!-- 修改编辑 -->
    <n-drawer v-model:show="drawerState.show" :width="700">
      <n-drawer-content :title="drawerState.title" closable>
        <MyTabs
          v-model="drawerState.active"
          class="sticky left-0 top--16 z-100 bg-#FFF py-16"
          :options="drawerTabs"
        />
        <div v-show="drawerState.active === 'detail'">
          <TaskForm
            ref="$taskForm"
            :project-id="projectId"
            :exe-id="drawerState.handleId"
            :is-lock="state.isLock"
            :scene="scene"
            @hide="drawerState.show = false"
            @reset="() => methods.getList(true)"
          />
        </div>
        <TaskComment
          v-if="drawerState.active === 'comment' && drawerState.handleType === 'person'"
          :exe-id="drawerState.handleId"
          @hide="drawerState.show = false"
        />
        <TaskHistory
          v-if="drawerState.active === 'history' && drawerState.handleType === 'person'"
          :exe-id="drawerState.handleId"
        />
      </n-drawer-content>
    </n-drawer>
  </div>
</template>
<script setup lang="jsx">
import { useWorkday } from '@/hooks/useWorkday'
import { useUserStore } from '@/store'
import TaskTable from './TaskTable.vue'
import TaskForm from './TaskForm.vue'
import TaskComment from './TaskComment.vue'
import TaskHistory from './TaskHistory.vue'
import { useCrudPro } from '@/hooks/useCrudPro'
import { usePermissionStore } from '@/store'
import _ from 'lodash-es'
import dayjs from 'dayjs'
import { gantt } from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import * as taskProjectApi from '@/api/taskProject'
import * as projectApi from '@/api/project'
defineOptions({ name: 'TaskGantt' })
const { hasPermission } = usePermissionStore()
const props = defineProps({
  // all | self
  scene: {
    type: String,
    default: 'all',
  },
  projectId: {
    type: String,
    default: '',
  },
  columns: {
    type: Array,
    default: () => [
      { label: '执行人', name: 'people', align: 'center' },
      { label: '执行范围', name: 'range', align: 'center' },
      { label: '工期(天)', name: 'workTime', align: 'center' },
      { label: '状态', name: 'state', align: 'center' },
    ],
  },
  listKey: {
    type: String,
    default: '',
  },
})
//查询切换
const query = reactive({
  //项目
  projectId: null,
  //模块(一级任务)
  moduleId: null,
  // 用户id
  executor: null,
  // 执行范围（文本）
  executionScope: null,
  // 部门id
  deptId: '',
  taskState: null,
})
const { isHigh } = useUserStore()
const { initCustomWorkday, isWorkday, isCustomWorkday, isAllWorkday } = useWorkday()
// 甘特图日期切换
const scaleMap = {
  day: {
    dateScale: '%d日',
    subscales: [
      {
        unit: 'month',
        step: 1,
        date: '%Y年%m月',
      },
    ],
  },
  month: {
    dateScale: '%m 月',
    subscales: [
      {
        unit: 'year',
        step: 1,
        date: '%Y年',
      },
    ],
  },
  year: {
    dateScale: '%Y年',
    subscales: [],
  },
}
const dateScale = computed(() => scaleMap[state.scaleUnit]['dateScale'])
const subscales = computed(() => scaleMap[state.scaleUnit]['subscales'])

const state = reactive({
  deptOptions: [],
  projectOptions: [],
  moduleOptions: [],
  devOptions: [],
  scopeOptions: [],
  loading: true,
  list: [],
  handles: [],
  showDropdown: false,
  x: 0,
  y: 0,
  currentHandle: [],
  timeOptions: [
    { label: '日', value: 'day' },
    { label: '月', value: 'month' },
    { label: '年', value: 'year' },
  ],
  scaleUnit: 'day',
  columnOptions: [
    { label: '一级模块', value: 'one' },
    { label: '二级模块', value: 'two' },
    { label: '三级模块', value: 'three' },
    { label: '执行人', value: 'person' },
    { label: '执行范围', value: 'scope' },
    { label: '评估', value: 'estimate' },
    { label: '排期', value: 'schedules' },
    { label: '状态', value: 'status' },
  ],
  haveColumnKeys: [],
  currentDate: null,
  currentExeId: null,
  currentDescribe: null,
  cupList: [],
  currentCupId: null,
  events: [],
  tableWidth: 0,
  currentTableCell: null,
  isLock: false,
  lockLoading: false,
  currentScrollTop: 0,
  currentScrollLeft: 0,
  listenScroll: false,
  statusOptions: [
    { label: '未开始', value: 0 },
    { label: '进行中', value: 1 },
    { label: '已完成', value: 2 },
  ],
  showHoliday: true,
  markList: new Set(),
})
const $taskTable = ref(null)
const $gantt = ref(null)

const methods = reactive({
  async getLock() {
    const { data } = await taskProjectApi.getLock(props.projectId)
    state.isLock = data === 1
  },
  setLock() {
    state.lockLoading = true
    taskProjectApi
      .setLock({ projectId: props.projectId, locks: state.isLock ? 0 : 1 })
      .then(() => {
        $message.success(`${state.isLock ? '解锁成功!' : '锁定成功!'}`)
        methods.getLock()
      })
      .finally(() => {
        state.lockLoading = false
      })
  },
  async getDeptOptions() {
    const { data } = await taskProjectApi.deptList()
    state.deptOptions = [
      { label: '全部', value: '' },
      ...data.map((v) => ({
        label: v.name,
        value: v.dept_id,
      })),
    ]
  },
  async getProjectOptions() {
    const { data } = await projectApi.hasTaskList({ deptId: query.deptId })
    state.projectOptions = data.map((item) => ({
      label: `${item.projectName} V.${item.projectVersion || 0}.${item.projectVersionMinor || 0}`,
      value: item.id,
    }))
  },
  async getModuleOptions() {
    const { data } = await taskProjectApi.moduleList({ projectId: query.projectId })
    state.moduleOptions = data
  },
  async getDevOptions() {
    const { data } = await projectApi.devPersonListPro({
      projectId: query.projectId,
      moduleId: query.moduleId,
      deptId: query.deptId,
    })
    state.devOptions = data
  },
  async getScopeOptions() {
    const { data } = await taskProjectApi.deptScope({
      projectId: query.projectId,
      moduleId: query.moduleId,
      executor: query.executor,
    })
    state.scopeOptions = data
  },
  getOptions() {
    methods.getDeptOptions()
    methods.getProjectOptions()
    methods.getModuleOptions()
    methods.getDevOptions()
    methods.getScopeOptions()
  },
  commonChange(level) {
    const map = [
      { level: 5, key: 'deptId', getOptions: methods.getDeptOptions },
      { level: 4, key: 'projectId', getOptions: methods.getProjectOptions },
      { level: 3, key: 'moduleId', getOptions: methods.getModuleOptions },
      { level: 2, key: 'executor', getOptions: methods.getDevOptions },
      { level: 1, key: 'executionScope', getOptions: methods.getScopeOptions },
    ]
    map.forEach((item) => {
      if (item.level < level) {
        query[item.key] = null
        item.getOptions()
      }
    })
    if (level === 5) {
      methods.getList()
    }
  },
  handleSearch() {
    methods.getList()
  },
  async getHaveColumnKeys() {
    const { columnSetting } = await taskProjectApi.getCol()
    state.haveColumnKeys = columnSetting
  },
  async getList(isScroll = false) {
    state.markList.clear()
    state.listenScroll = false
    if (props.listKey && !hasPermission(props.listKey)) return
    state.loading = true
    if (props.scene === 'self') {
      query['projectId'] = props.projectId
      methods.getLock()
    }
    await methods.getHaveColumnKeys()
    await initCustomWorkday()
    const { data } = await taskProjectApi.list(query)
    const result = methods.formatToTable(data)
    state.list = result.concat({ id: null })
    methods.reloadGantt(methods.formatToGantt(result))
    nextTick().then(() => {
      state.loading = false
      $taskTable.value.bindDrag()
      // 是否滚动到上一次位置
      // console.log(isScroll, state.currentScrollTop)
      if (isScroll) {
        $taskTable?.value?.scrollTo({ top: state.currentScrollTop })
        gantt.scrollTo(state.currentScrollLeft, state.currentScrollTop)
      } else {
        state.currentScrollTop = 0
        state.currentScrollLeft = 0
      }
      state.listenScroll = true
    })
  },
  // 获取里程碑列表
  async getCupList() {
    gantt.addMarker({
      start_date: new Date(),
      css: 'today',
      text: '今日',
    })
    if (props.scene !== 'self') return
    const { data = [] } = await taskProjectApi.cupList({ projectId: props.projectId })
    state.cupList = data
    data.forEach((item) => {
      gantt.addMarker({
        start_date: new Date(item.markCupTime),
        css: 'today',
        text: item.describe,
      })
    })
  },
  initGantt() {
    // 清空之前的配置
    gantt.clearAll()
    // 默认配置
    gantt.config.xml_date = '%Y-%m-%d'
    // 第一层显示年
    gantt.config.subscales = subscales.value
    // 第二次时间格式
    gantt.config.date_scale = dateScale.value
    // 时间跨度
    gantt.config.scale_unit = state.scaleUnit
    // 设置中文
    gantt.i18n.setLocale('cn')
    // 设置为只读
    gantt.config.readonly = true
    //设置甘特图表头高度
    gantt.config.scale_height = 75
    // 滚动时间为最早时间
    // gantt.config.initial_scroll = false
    //配置甘特图容器中的行列滚动条
    gantt.config.layout = {
      css: 'gantt_container',
      rows: [
        {
          cols: [
            { view: 'grid', id: 'grid', scrollX: 'scrollHor', scrollY: 'scrollVer' },
            { resizer: true, width: '0' },
            { view: 'timeline', id: 'timeline', scrollX: 'scrollHor', scrollY: 'scrollVer' },
            { view: 'scrollbar', scroll: 'y', id: 'scrollVer', height: 0, width: 0 },
          ],
        },
        { view: 'scrollbar', scroll: 'x', id: 'scrollHor' },
      ],
    }
    // 滚动条尺寸
    gantt.config.scroll_size = 0
    // 设置行高为 32 像素
    gantt.config.row_height = 32
    // 设置任务条高度为 32 像素
    gantt.config.bar_height = 28
    // 禁止任务被选中
    gantt.config.select_task = false
    // 重新绘制保留当前位置
    gantt.config.preserve_scroll = true
    // 显示列配置
    gantt.config.columns = props.columns
    // 是否显示左侧任务
    gantt.config.show_grid = false
    // 取消错误提示
    gantt.config.show_errors = false
    // 任务着色
    gantt.templates.task_class = function (start, end, task) {
      switch (task.id) {
        case 'null':
          return 'none'
        default:
          return 'default'
      }
    }
    // gantt.ignore_time = function (date) {
    //   if (!isAllWorkday(date) && !state.showHoliday) return true
    // }
    gantt.templates.scale_cell_class = function (date) {
      return !isWorkday(date) ? 'm-holiday' : ''
    }
    gantt.templates.timeline_cell_class = function (_, date) {
      return !isAllWorkday(date) && state.scaleUnit === 'day' ? 'm-holiday' : ''
    }
    if (props.scene === 'self') {
      const event1 = gantt.attachEvent('onContextMenu', methods.handleGanttMenu)
      state.events.push(event1)
    }
    //任务条显示内容
    gantt.templates.task_text = methods.renderTask
    gantt.plugins({
      marker: true,
    })
    // 初始化甘特图
    gantt.init($gantt.value)

    // 监听甘特图滚动
    nextTick(() => {
      const event2 = gantt.attachEvent('onGanttScroll', methods.handleGanttScroll)
      state.events.push(event2)
    })
  },
  formatToTable(data) {
    return data.reduce(
      (res1, { projectName, projectId, teskName, id, children, someone, ...other }) => {
        const info1 = {
          name0: projectName,
          id0: projectId,
          name1: teskName,
          id1: id,
          count1: someone,
        }
        if (!children || children.length === 0) {
          return res1.concat([{ id, ...other, ...info1 }])
        } else {
          return res1.concat(
            children.reduce((res2, { teskName, id, children, someone, ...other }) => {
              const info2 = {
                name2: teskName,
                id2: id,
                count2: someone,
              }
              if (!children || children.length === 0) {
                return res2.concat([{ id, ...other, ...info1, ...info2 }])
              } else {
                return res2.concat(
                  children.reduce((res3, { teskName, id, children, someone, ...other }) => {
                    const info3 = {
                      name3: teskName,
                      id3: id,
                      count3: someone,
                    }
                    if (!children || children.length === 0) {
                      return res3.concat([{ id, ...other, ...info1, ...info2, ...info3 }])
                    } else {
                      return res3.concat(
                        children.reduce((res4, user) => {
                          return res4.concat([{ ...user, ...info1, ...info2, ...info3 }])
                        }, [])
                      )
                    }
                  }, [])
                )
              }
            }, [])
          )
        }
      },
      []
    )
  },
  formatToGantt(result) {
    return _.cloneDeep(result).reduce((data, item) => {
      if (item.startTime && item.endTime) {
        let res = [
          {
            id: item.exeId || `${item.id}-id`,
            render: 'split',
            unscheduled: true,
          },
          {
            id: `${item.exeId || item.id}-bid`,
            start_date: dayjs(item.startTime).format('YYYY-MM-DD'),
            end_date:
              dayjs(item.endTime).format('HH:mm:ss') === '00:00:00'
                ? dayjs(item.endTime).format('YYYY-MM-DD')
                : dayjs(item.endTime).add(1, 'day').format('YYYY-MM-DD'),
            parent: item.exeId || item.id,
            num: item.extensionTime ? item.intDuration : item.actualDuration,
            type: 'base',
          },
        ]
        if (item.markingTime) {
          res = res.concat(
            item.markingTime.split(',').map((val) => {
              const [id, start_date] = val.split('|')
              const startDate = dayjs(start_date).format('YYYY-MM-DD')
              state.markList.add(startDate)
              return {
                id,
                start_date: startDate,
                duration: 1,
                parent: item.exeId || item.id,
                type: 'mark',
                num: 1,
              }
            })
          )
        }
        if (item.extensionTime) {
          res = res.concat([
            {
              id: `${item.exeId || item.id}-did`,
              start_date: dayjs(item.endTime).format('YYYY-MM-DD'),
              end_date: dayjs(item.extensionTime).format('YYYY-MM-DD'),
              parent: item.exeId || item.id,
              type: 'extension',
              num: item.actualDuration - item.intDuration,
            },
          ])
        }
        return data.concat(res)
      } else {
        return data.concat([{ ...item, id: item.exeId || `${item.id}-id`, unscheduled: true }])
      }
    }, [])
  },
  renderTask(start, end, task) {
    let color = ''
    if (task.type === 'base') {
      let baseColor = '#0a56d8'
      let holidayColor = '#13479f'
      let width = 70
      let currentDate = dayjs(start)
      let endDate = dayjs(end)
      const list = []
      while (currentDate.format('YYYY-MM-DD') != endDate.format('YYYY-MM-DD')) {
        if (!(!state.showHoliday && !isAllWorkday(currentDate))) {
          if (list.at(-1)?.type === isAllWorkday(currentDate)) {
            list.at(-1).value += 1
          } else {
            list.push({ type: isAllWorkday(currentDate), value: 1 })
          }
        }
        currentDate = currentDate.add(1, 'day')
      }
      const { res } = list.reduce(
        ({ res, start }, { type, value }) => {
          let currentColor = type ? baseColor : holidayColor
          return {
            res:
              res +
              `, ${currentColor} ${start * width}px, ${currentColor} ${(start + value) * width}px`,
            start: start + value,
          }
        },
        {
          res: ``,
          start: 0,
        }
      )
      color = `linear-gradient(to right${res})`
    } else if (task.type === 'mark') {
      color = 'purple'
    } else if (task.type === 'extension') {
      color = '#fad354'
    }
    return `<div data-type="${task.type}" data-parent="${task.parent}" style='color:#fff;font-size:12px;text-align:right;padding-right:12px;background: ${color};min-width: 40px;'>${task.num}天</div>`
  },
  reloadGantt(data) {
    gantt.clearAll()
    gantt.parse({ data })
    gantt.render()
    methods.getCupList()
  },
  handleToggleUnit() {
    // 第一层显示年
    gantt.config.subscales = subscales.value
    // 第二次时间格式
    gantt.config.date_scale = dateScale.value
    // 时间跨度
    gantt.config.scale_unit = state.scaleUnit
    gantt.render()
  },
  handleToggleHoliday() {
    state.showHoliday = !state.showHoliday
    gantt.ignore_time = function (date) {
      if (
        !isAllWorkday(date) &&
        !state.showHoliday &&
        !state.markList.has(dayjs(date).format('YYYY-MM-DD'))
      )
        return true
    }
    gantt.render()
  },
  handleTableScroll(event) {
    if (!state.listenScroll) return
    // console.log('table-scroll', event.target.scrollTop)
    state.currentScrollTop = event.target.scrollTop
    gantt.scrollTo(null, event.target.scrollTop)
  },
  handleGanttScroll(_, __, left, top) {
    if (!state.listenScroll) return
    // console.log('gantt-scroll', top)
    state.currentScrollTop = top
    state.currentScrollLeft = left
    $taskTable?.value?.scrollTo({ top })
  },
  handleClickOutSize() {
    state.showDropdown = false
    if (state.currentTableCell) {
      state.currentTableCell.setAttribute('data-menu-active', 'nomarl')
      state.currentTableCell = null
    }
  },
  //type: person module,action: add view edit delete
  handleTableMenu(e, row) {
    state.currentTableCell = e.target.closest('td.n-data-table-td')
    const keyMap = {
      // name0: ['id0', '项目','level', 'countKey'],
      name1: ['id1', '一级模块', 1, 'count1'],
      name2: ['id2', '二级模块', 2, 'count2'],
      name3: ['id3', '三级模块', 3, 'count3'],
      executorName: ['exeId', '执行人'],
      taskState: ['exeId', '执行人'],
    }
    state.showDropdown = false
    const key = state.currentTableCell.dataset.colKey
    if (Object.keys(keyMap).includes(key) && row[key] !== undefined) {
      state.currentTableCell.setAttribute('data-menu-active', 'active')
      nextTick().then(() => {
        const type = ['executorName', 'taskState'].includes(key) ? 'person' : 'module'
        const [idKey, moduleName, level, countKey] = keyMap[key]
        const id = row[idKey]
        const count = row[countKey]
        const value = row[key]
        state.currentHandle = { type, id, value, moduleName, level, count }
        state.handles = methods.generateHandels(key, type, level, count)
        state.showDropdown = true
        state.x = e.clientX
        state.y = e.clientY
      })
    }
  },
  generateHandels(key, type, level, count) {
    const result = []
    if (type === 'person') {
      if (key === 'taskState') {
        if (hasPermission('TaskExe:update')) {
          result.push({ label: '编辑状态', key: 'edit' })
        }
      } else {
        if (hasPermission('TaskExe:view') && props.scene === 'all') {
          result.push({ label: '查看', key: 'view' })
        }
        if (hasPermission('TaskExe:update')) {
          result.push({ label: '编辑', key: 'edit' })
        }
        if (
          hasPermission('TaskExe:delete') &&
          props.scene === 'self' &&
          (!state.isLock || isHigh)
        ) {
          result.push({ label: '删除', key: 'delete' })
        }
      }
    } else if (type === 'module') {
      if (hasPermission('TaskModule:view') && props.scene === 'all') {
        result.push({ label: '查看', key: 'view' })
      }
      if (hasPermission('TaskModule:update') && props.scene === 'self') {
        result.push({ label: '编辑', key: 'edit' })
      }
      if (
        hasPermission('TaskModule:delete') &&
        props.scene === 'self' &&
        (!state.isLock || isHigh)
      ) {
        result.push({ label: '删除', key: 'delete' })
      }
      if (hasPermission('TaskModule:add') && props.scene === 'self' && level < 3 && count === 0) {
        result.push({ label: '添加下级任务', key: 'add' })
      }
    }
    return result
  },
  handleGanttMenu(_, __, event) {
    event.preventDefault()
    if (state.scaleUnit !== 'day') return
    const target = event.target || event.srcElement
    const isEmpty = target.classList.contains('gantt_task_cell')
    const isDay = target.classList.contains('gantt_scale_cell') && !target.innerText.includes('年')
    const isMark = target?.getAttribute('data-type') === 'mark'
    const container = document.querySelector('.myGantt .gantt_hor_scroll')
    const containerPos = document.querySelector('.myGantt').getBoundingClientRect()
    // console.log(event, containerPos, container)
    let mouseX = event.clientX - containerPos.left + (container?.scrollLeft || 0)
    // 将坐标转换为日期
    const gantDate = gantt.dateFromPos(mouseX)
    const cellDate = dayjs(gantDate).format('YYYY-MM-DD')
    // console.log(cellDate, event, isEmpty, isDay, isMark)

    // 日期右键
    if (isDay) {
      const handles = []
      //设置里程
      if (hasPermission('mark_gantt_cup') && state.isLock) {
        state.currentDate = cellDate
        state.showDropdown = false
        state.x = event.clientX
        state.y = event.clientY
        const current = state.cupList.find((item) => item.markCupTime.includes(cellDate))
        if (current) {
          state.currentCupId = current.id
          handles.push({ label: '取消里程', key: 'cancelCup' })
        } else {
          handles.push({ label: '设置里程', key: 'setCup' })
        }
        state.showDropdown = true
      }
      //设置工作日/取消工作日
      // if (hasPermission('set_gantt_workday')) {
      //   state.currentDate = cellDate
      //   state.showDropdown = false
      //   state.x = event.clientX
      //   state.y = event.clientY
      //   if (isCustomWorkday(cellDate)) {
      //     handles.push({ label: '取消工作日', key: 'cancelWorkday' })
      //   } else if (!isWorkday(gantDate)) {
      //     handles.push({ label: '设置工作日', key: 'setWorkday' })
      //   }
      //   state.showDropdown = true
      // }
      state.handles = handles
    } else {
      //单元格右键
      //为空/权限/锁定可以进行标记
      if (isEmpty && hasPermission('mark_gantt_date') && state.isLock) {
        const id = target?.closest('.gantt_task_row')?.getAttribute('data-task-id')
        if (!id.includes('-id')) {
          state.currentDate = cellDate
          state.showDropdown = false
          state.currentExeId = id
          state.x = event.clientX
          state.y = event.clientY
          state.handles = [{ label: '设置标记', key: 'setMark' }]
          state.showDropdown = true
        }
      }
      //有标记可以取消标记
      if (isMark && hasPermission('mark_gantt_date') && state.isLock) {
        state.currentDate = cellDate
        state.showDropdown = false
        state.currentExeId = target?.getAttribute('data-parent')
        state.x = event.clientX
        state.y = event.clientY
        state.handles = [{ label: '取消标记', key: 'cancelMark' }]
        state.showDropdown = true
      }
    }
  },
  handleSelect(e) {
    // console.log(state.currentHandle)
    methods.handleClickOutSize()
    if (e === 'add') {
      const { id, level } = state.currentHandle
      drawerMethods.handleAdd(id, level)
    } else if (e === 'view') {
      drawerMethods.handleView(state.currentHandle)
    } else if (e === 'edit') {
      drawerMethods.handleEdit(state.currentHandle)
    } else if (e === 'delete') {
      drawerMethods.handleDelete(state.currentHandle)
    } else if (['setMark', 'cancelMark'].includes(e)) {
      methods.handleMark(e === 'setMark' ? 0 : 1)
    } else if (['setCup', 'cancelCup'].includes(e)) {
      methods.handleCup(e)
    } else if (['setWorkday', 'cancelWorkday'].includes(e)) {
      methods.handleWorkday(e)
    }
  },
  // type 0设置标记 1取消标记
  handleMark(type) {
    const dialog = $dialog.warning({
      title: '提示',
      content: `确定${type === 0 ? '设置' : '取消'}标记${state.currentDate}?`,
      negativeText: '取消',
      positiveText: '确定',
      positiveButtonProps: {
        color: '#0A56D8FF',
      },
      async onPositiveClick() {
        try {
          dialog.loading = true
          await taskProjectApi.setMark({
            projectExeId: state.currentExeId,
            markingTime: `${state.currentDate} 00:00:00`,
            cancel: type,
          })
          dialog.loading = false
          $message.success(`${type === 0 ? '设置' : '取消'}标记成功！`)
          methods.getList(true)
        } catch (error) {
          console.log('error:', error)
          dialog.loading = false
        }
      },
    })
  },
  handleCup(type) {
    state.currentDescribe = null
    const dialog = $dialog.warning({
      title: '提示',
      content: () => (
        <>
          <div class="mb-10">
            确定{type === 'setCup' ? '设置' : '取消'}项目里程{state.currentDate}？
          </div>
          <n-input
            v-show={type === 'setCup'}
            v-model:value={state.currentDescribe}
            placeholder="请输入描述"
            required
            maxlength={100}
          />
        </>
      ),
      negativeText: '取消',
      positiveText: '确定',
      positiveButtonProps: {
        color: '#0A56D8FF',
      },
      async onPositiveClick() {
        if (!state?.currentDescribe?.length && type === 'setCup') {
          $message.warning(`请输入描述!`)
          return false
        }
        try {
          dialog.loading = true
          if (type === 'setCup') {
            await taskProjectApi.cupAdd({
              projectId: props.projectId,
              markCupTime: `${state.currentDate} 00:00:00`,
              describe: state.currentDescribe,
            })
          } else {
            await taskProjectApi.cupDel(state.currentCupId)
          }
          dialog.loading = false
          $message.success(`${type === 'setCup' ? '设置' : '取消'}项目里程成功！`)
          methods.getList(true)
        } catch (error) {
          console.log('error:', error)
          dialog.loading = false
        }
      },
    })
  },
  handleWorkday(type) {
    const dialog = $dialog.warning({
      title: '提示',
      content: `确定${type === 'setWorkday' ? '设置' : '取消'}工作日${state.currentDate}?`,
      negativeText: '取消',
      positiveText: '确定',
      positiveButtonProps: {
        color: '#0A56D8FF',
      },
      async onPositiveClick() {
        try {
          dialog.loading = true
          if (type === 'setWorkday') {
            await taskProjectApi.addCustomWorkday({ calendarDate: state.currentDate })
          } else {
            await taskProjectApi.delCustomWorkday({ calendarDate: state.currentDate })
          }
          dialog.loading = false
          $message.success(`${type === 'setWorkday' ? '设置' : '取消'}工作日成功！`)
          methods.getList(true)
        } catch (error) {
          console.log('error:', error)
          dialog.loading = false
        }
      },
    })
  },
})

const {
  model,
  $form,
  handleEdit: handleEditCol,
  handleSubmit: handleSubmitCol,
} = useCrudPro({
  name: '列',
  initForm: {
    id: null,
    columnSetting: [],
  },
  apis: {
    edit: taskProjectApi.setCol,
    info: taskProjectApi.getCol,
  },
  handleReset() {
    methods.getHaveColumnKeys()
  },
})
const $taskForm = ref(null)
const drawerTabs = computed(() => {
  const ary = [{ label: '详情', value: 'detail' }]
  if (drawerState.handleType === 'person') {
    return ary.concat([
      { label: '评论', value: 'comment' },
      { label: '历史', value: 'history' },
    ])
  } else {
    return ary
  }
})
const drawerState = reactive({
  active: 'detail',
  show: false,
  title: '',
  handleType: '',
  handleId: '',
})
const drawerMethods = reactive({
  handleAdd(parentId, level) {
    drawerState.active = 'detail'
    drawerState.title = '添加任务'
    drawerState.show = true
    nextTick(() => {
      $taskForm.value.initModel('module', 'add', { parentId, level })
    })
  },
  handleView({ type, id }) {
    // console.log(type, id)
    drawerState.active = 'detail'
    drawerState.handleType = type
    drawerState.handleId = id
    drawerState.title = type === 'module' ? '查看任务' : '查看任务执行'
    drawerState.show = true
    nextTick(() => {
      $taskForm.value.initModel(type, 'view', { id })
    })
  },
  handleEdit({ type, id }) {
    // console.log(type, id)
    drawerState.active = 'detail'
    drawerState.handleType = type
    drawerState.handleId = id
    drawerState.title = type === 'module' ? '修改任务' : '修改任务执行'
    drawerState.show = true
    nextTick(() => {
      $taskForm.value.initModel(type, 'edit', { id })
    })
  },
  handleDelete({ type, id, value, moduleName }) {
    const dialog = $dialog.warning({
      title: '提示',
      content: `确定删除${moduleName}：(${value})？`,
      negativeText: '取消',
      positiveText: '确定',
      positiveButtonProps: {
        color: '#0A56D8FF',
      },
      async onPositiveClick() {
        try {
          dialog.loading = true
          if (type === 'module') {
            await taskProjectApi.delModule(id)
          } else if (type === 'person') {
            await taskProjectApi.delPerson(id)
          }
          dialog.loading = false
          $message.success('删除成功')
          methods.getList(true)
        } catch (error) {
          console.log('error:', error)
          dialog.loading = false
        }
      },
    })
  },
})

onBeforeMount(() => {
  if (props.scene === 'self') {
    query.projectId = props.projectId
    if (props.projectId) {
      methods.getOptions()
    }
  } else {
    methods.getOptions()
  }
})
onMounted(async () => {
  methods.initGantt()
  if (props.scene === 'self') {
    if (props.projectId) {
      methods.getList()
    }
  } else {
    methods.getList()
  }
})
onBeforeUnmount(() => {
  state.events.forEach((item) => {
    gantt.detachEvent(item)
  })
})
watch(
  () => props.projectId,
  (val) => {
    methods.getOptions()
    if (props.scene === 'self' && val) {
      methods.getList()
    }
  }
)
</script>
<style scoped lang="scss">
/* common styles for overriding borders/progress color */
.gantt_task_line {
  border-color: rgba(0, 0, 0, 0.25);
}
.gantt_task_line .gantt_task_progress {
  background-color: rgba(0, 0, 0, 0.25);
}

/* 任务块 */
.gantt_task_line.default {
  background-color: #0a56d8;
  border-radius: 4px;
}
.gantt_task_line.none {
  background-color: transparent;
  border: 0;
  border-radius: 4px;
}

.myGantt .gantt_layout .gantt_layout_cell.timeline_cell.gantt_layout_outer_scroll {
  pointer-events: none;
  width: 100% !important;
}
.myGantt .gantt_layout .gantt_layout_cell.scrollVer_cell {
  opacity: 0 !important;
  pointer-events: none;
  width: 0 !important;
}
/* 边框 */
.gantt_container {
  border: 0;
  border: 1px solid rgb(239, 239, 245);
}
.gantt_task_scale,
.gantt_grid_scale,
.gantt_scale_line {
  border: 0;
  border-bottom: 1px solid rgb(239, 239, 245);
}
.weekend {
  background: #fde4c7;
  color: #fff;
}
</style>
<style lang="scss">
.myGantt .gantt_task_scale .gantt_scale_line:nth-of-type(2) .gantt_scale_cell {
  cursor: pointer;
}
.myGantt .gantt_data_area .gantt_task_cell {
  cursor: pointer;
}
.myGantt {
  .gantt_scale_cell {
    color: rgba(104, 111, 124, 1);
  }
  .gantt_scale_cell.m-holiday {
    background: #f5f6fb;
    border-bottom: 1px solid #cecece;
  }
  .gantt_task_cell.m-holiday {
    background: #f5f6fb;
  }
}
</style>
